﻿#include <iostream>
#include "httplib.h"
#include "rapidjson//document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/error/en.h"

#include <filesystem>
#include <fstream>

using namespace std;
using namespace httplib;
using namespace rapidjson;
namespace fs = filesystem;

#define json_path "./config/webInfo.json"

class WebInfo
{
public:
    static string *path;
    static string *host;
    static string *ws_path;
    static string *dir_root;
    static int *port;
    static bool *ok;
};

bool isJSONFormat(const string &jsonStr)
{
    Document doc;
    if (doc.Parse(jsonStr.c_str()).HasParseError())
    {
        // 解析失败，字符串不是有效的 JSON 格式
        const char *error = GetParseError_En(doc.GetParseError());
        return false;
    }
    return true;
}
string getFileNameFromPath(const string &path)
{
    // 通过查找路径中的最后一个 '/' 或 '' 来获取文件名
    size_t pos = path.find_last_of("/");
    if (pos != string::npos)
    {
        return path.substr(pos + 1);
    }
    return path;
}

void start_exe(string exe_path, string param)
{
    /*     int a = 0, code;
        while (a++ < 12)
        {
            string killCmd = "taskkill /F /IM " + getFileNameFromPath(exe_path);
                code = system(killCmd.c_str());

            if (!code)
                break;

            Sleep(10);
        } */

    // system(("start " + exe_path + " " + param).c_str());
    system((exe_path + " " + param).c_str());

    /* SHELLEXECUTEINFO info = {0};
    info.cbSize = sizeof(info);
    info.fMask = SEE_MASK_NOCLOSEPROCESS;
    info.hwnd = NULL;
    info.lpVerb = NULL;
    info.lpFile = exe_path.c_str();
    info.lpParameters = param.c_str();
    info.lpDirectory = NULL;
    info.nShow = SW_SHOW;

    if (ShellExecuteEx(&info))
    {
        WaitForSingleObject(info.hProcess, INFINITE);
        CloseHandle(info.hProcess);
    }
    else
    {
        cout << "Failed to open program." << endl;
    } */
}

void start_ws(string &origin)
{
    const string dir_root = fs::absolute(*WebInfo::dir_root).generic_string();
    string cmd = "\"{\\\"allowed_origins\\\": [\\\"" + origin + "\\\"], \\\"init\\\": true,\\\"dir_root\\\": \\\"" + dir_root + "\\\"}\"";

    if (fs::exists(*WebInfo::ws_path))
    {
        string path = fs::absolute(*WebInfo::ws_path).generic_string();
        int ws_port = system((path + " " + cmd).c_str());

        cmd = "\"{\\\"allowed_origins\\\": [\\\"" + origin + "\\\"],\\\"dir_root\\\": \\\"" + dir_root + "\\\"}\"";
        origin = origin + "?ws_port=" + to_string(ws_port);
        start_exe(path, cmd);
    }
    else
    {
        cerr << "ws服务执行文件不存在:";

        HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
        SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | 4);
        cout << endl
             << fs::absolute(*WebInfo::ws_path).generic_string() << endl;
        SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | 7);
    }
}

void read_jsonfile(string json_filepath = json_path)
{
    if (fs::exists(json_filepath))
    {
        ifstream fin;

        fin.open(json_filepath, ios::in);

        if (!fin)
        {
            cerr << "文件打开失败" << endl;
        }

        string line;
        string text = "";
        while (getline(fin, line))
        {
            text += line;
        }

        Document doc;
        doc.Parse(text.c_str());

        if (doc.HasParseError() || !doc.IsObject())
        {
            cout << "Failed to parse JSON object at line " << endl;
            return;
        }

        delete WebInfo::path;
        WebInfo::path = new string(doc["path"].GetString());

        delete WebInfo::host;
        WebInfo::host = new string(doc["host"].GetString());

        if (doc.HasMember("ws_path"))
        {
            delete WebInfo::ws_path;
            WebInfo::ws_path = new string(doc["ws_path"].GetString());
        }

        string dr = "";
        if (doc.HasMember("dir_root"))
        {
            dr = doc["dir_root"].GetString();
        }
        delete WebInfo::dir_root;
        WebInfo::dir_root = new string(dr);

        delete WebInfo::port;
        WebInfo::port = new int(doc["port"].GetInt());

        delete WebInfo::ok;
        WebInfo::ok = new bool(true);

        fin.close();
    }
    else
    {
        cout << "文件不存在" << endl;
    }
}

void setParam(string paramStr)
{
    Document doc;
    doc.Parse(paramStr.c_str());

    if (doc.HasParseError() || !doc.IsObject())
    {
        cout << "Failed to parse JSON object at line " << endl;

        // 如果不是json格式就读取本地文件
        read_jsonfile(paramStr);
    }

    delete WebInfo::path;
    WebInfo::path = new string(doc["path"].GetString());

    delete WebInfo::host;
    WebInfo::host = new string(doc["host"].GetString());

    if (doc.HasMember("ws_path"))
    {
        delete WebInfo::ws_path;
        WebInfo::ws_path = new string(doc["ws_path"].GetString());
    }

    string dr = "";
    if (doc.HasMember("dir_root"))
    {
        dr = doc["dir_root"].GetString();
    }
    delete WebInfo::dir_root;
    WebInfo::dir_root = new string(dr);

    delete WebInfo::port;
    WebInfo::port = new int(doc["port"].GetInt());

    delete WebInfo::ok;
    WebInfo::ok = new bool(true);
}

void start_server()
{
    Server svr;

    string abs_path = fs::absolute(*WebInfo::path).generic_string();
    size_t pos = 0;

    while ((pos = abs_path.find("\\", pos)) != string::npos)
    {
        abs_path.replace(pos, 1, "/");
        pos++;
    }

    const string origin = "http://" + *WebInfo::host + ":" + to_string(*WebInfo::port);
    string url = origin;
    if (*WebInfo::ws_path != "")
        start_ws(url);
    else
        cout << "无 websocket 服务器" << endl;

    string line = "--------------------------\n";

    cout << line << endl;
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | 4);
    cout << "关闭该窗体以停止http服务" << endl;
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | 7);
    cout << endl
         << line
         << "本地路径: " << abs_path << endl
         << "主机地址: " << *WebInfo::host << endl
         << "服务端口: " << *WebInfo::port << endl
         << line
         << origin << endl
         << line
         << endl;

    // 设置静态文件根目录
    svr.set_base_dir(WebInfo::path->c_str());

    svr.Get("/", [](const Request &req, Response &res)
            { res.set_redirect("/index.html"); });

    string cmd = "start \"\" \"" + url + "\"";
    system(cmd.c_str());

    cout << "Http 服务已在端口 " << *WebInfo::port << " 上运行" << endl;

    svr.listen(WebInfo::host->c_str(), *WebInfo::port);
}

string *WebInfo::path = new string();
string *WebInfo::host = new string();
string *WebInfo::ws_path = new string();
string *WebInfo::dir_root = new string();
int *WebInfo::port = new int();
bool *WebInfo::ok = new bool(false);

int main(int argc, char *argv[])
{

    if (argc < 2)
    {
        cout << "未传参" << endl;
        read_jsonfile();
    }
    else
    {
        // string json = "{\"path\":\"E:/Project/CPP/test/5/en/dist\",\"host\":\"127.0.0.1\",\"port\":8080}";
        // string json = "{\"path\":\"./dist\",\"host\":\"127.0.0.1\",\"port\":8080}";
        setParam(argv[1]);
    }

    if (*WebInfo::ok)
    {
        start_server();
    }

    delete WebInfo::path;
    delete WebInfo::host;
    delete WebInfo::ws_path;
    delete WebInfo::dir_root;
    delete WebInfo::port;
    delete WebInfo::ok;

    return 0;
}